//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

//#include "Graphics/GLshell/StateManager.h"

namespace Engine
{
namespace Graphics
{
	
	//
	// Pixel Format
	//

	struct EPixelFormat
	{
		enum type
		{
			_UNKNOWN		= 0,

			// flags
			_UNSIGNED		= 0x010000,
			_SIGNED			= 0x020000,
			_NORMALIZED		= 0x040000,		// bits
			_FLOAT			= 0x080000,		// bytes
			_COMPRESSED		= 0x800000,		// index
			_COLOR			= 0x100000,
			_DEPTH			= 0x200000,		// bytes
			_STENCIL		= 0x400000,		// bits

			// unsigned normalized
			ALPHA8			= _UNSIGNED | _NORMALIZED | _COLOR | 0x0008,	//  8 bit
			R5_G6_B5		= _UNSIGNED | _NORMALIZED | _COLOR | 0x5650,	// 16 bit
			RGB8			= _UNSIGNED | _NORMALIZED | _COLOR | 0x8880,	// 24 bit
			RGB5_A1			= _UNSIGNED | _NORMALIZED | _COLOR | 0x5551,	// 16 bit
			RGBA4			= _UNSIGNED | _NORMALIZED | _COLOR | 0x4444,	// 16 bit
			RGBA8			= _UNSIGNED | _NORMALIZED | _COLOR | 0x8888,	// 32 bit
			// (EXT_texture_rg)
			R8				= _UNSIGNED | _NORMALIZED | _COLOR | 0x8000,	//  8 bit
			RG8				= _UNSIGNED | _NORMALIZED | _COLOR | 0x8800,	// 16 bit

			// float (EXT_texture_storage)
			RGBA32F			= _FLOAT | _COLOR | 0x4444,		// 128 bit
			RGBA16F			= _FLOAT | _COLOR | 0x2222,		// 64 bit
			RGB32F			= _FLOAT | _COLOR | 0x4440,		// 96 bit
			RGB16F			= _FLOAT | _COLOR | 0x2220,		// 48 bit
			RG32F			= _FLOAT | _COLOR | 0x4400,		// 64 bit
			RG16F			= _FLOAT | _COLOR | 0x2200,		// 32 bit
			R32F			= _FLOAT | _COLOR | 0x4000,		// 32 bit
			R16F			= _FLOAT | _COLOR | 0x2000,		// 16 bit
			ALPHA32F		= _FLOAT | _COLOR | 0x0004,		// 32 bit
			ALPHA16F		= _FLOAT | _COLOR | 0x0002,		// 16 bit


			// depth
			D16				= _DEPTH | 0x200,				// 16 bit
			D24				= _DEPTH | 0x300,				// 24 bit
			D32				= _DEPTH | 0x400,				// 32 bit

			// stencil
			S1				= _STENCIL | 0x1,				// 1 bit (OES_stencil1)
			S4				= _STENCIL | 0x4,				// 4 bit (OES_stencil4)
			S8				= _STENCIL | 0x8,				// 8 bit

			// depth stencil
			D24_S8			= _DEPTH | _STENCIL | 0x308,	// 32 bit (OES_packed_depth_stencil)


			// compressed
			RGB_ETC1		= _COMPRESSED | _COLOR | 0x1,	// 4 bit
		};


		// Utils
		struct StaticUtils
		{
			template <type E> struct IsCompressed		{ enum { value = ((int(E) & int(_COMPRESSED)) == _COMPRESSED) }; };
			template <type E> struct IsColor			{ enum { value = ((int(E) & int(_COLOR)) == _COLOR) }; };
			template <type E> struct IsDepth			{ enum { value = ((int(E) & int(_DEPTH)) == _DEPTH) }; };
			template <type E> struct IsStencil			{ enum { value = ((int(E) & int(_STENCIL)) == _STENCIL) }; };
			template <type E> struct IsDepthStencil		{ enum { value = ((int(E) & (int(_DEPTH) | int(_STENCIL))) == (int(_DEPTH) | int(_STENCIL))) }; };
			template <type E> struct IsNormalizedInt	{ enum { value = ((int(E) & int(_NORMALIZED)) == _NORMALIZED) }; };
			template <type E> struct IsFloat			{ enum { value = ((int(E) & int(_FLOAT)) == _FLOAT) }; };
		};

		struct Utils
		{
			static bool IsCompressed (type E)		{ return ((int(E) & int(_COMPRESSED)) == _COMPRESSED); }
			static bool IsColor (type E)			{ return ((int(E) & int(_COLOR)) == _COLOR); }
			static bool IsDepth (type E)			{ return ((int(E) & int(_DEPTH)) == _DEPTH); }
			static bool IsStencil (type E)			{ return ((int(E) & int(_STENCIL)) == _STENCIL); }
			static bool IsDepthStencil (type E)		{ return ((int(E) & (int(_DEPTH) | int(_STENCIL))) == (int(_DEPTH) | int(_STENCIL))); }
			static bool IsNormalizedInt (type E)	{ return ((int(E) & int(_NORMALIZED)) == _NORMALIZED); }
			static bool IsFloat (type E)			{ return ((int(E) & int(_FLOAT)) == _FLOAT); }
		};
		

		static bool GetFormat (gles::GLenum &ifmt, gles::GLenum &fmt, gles::GLenum &type, uint &bpp, const EPixelFormat::type format);
		static bool GetTexDataFormat (gles::GLenum &fmt, gles::GLenum &type, const EPixelFormat::type format);
		static bool GetCompressedTexFormat (gles::GLenum &fmt, const EPixelFormat::type format);
		static bool GetTexStorageFormat (gles::GLenum &ifmt, const EPixelFormat::type format);
		static bool GetBitPerPixel (uint &bpp, const EPixelFormat::type format);

		static bool GetImageSize (OUT usize &imgSize, const uvec2 &dim, const EPixelFormat::type format);
	};



	// GetTexDataFormat
	inline bool EPixelFormat::GetTexDataFormat (gles::GLenum &fmt, gles::GLenum &type, const EPixelFormat::type format)
	{
		gles::GLenum	ifmt = 0;
		uint			bpp  = 0;
		bool			res	 = GetFormat( ifmt, fmt, type, bpp, format );
		return ( res and fmt != 0 and type != 0 );
	}
	
	// GetCompressedTexFormat
	inline bool EPixelFormat::GetCompressedTexFormat (gles::GLenum &ifmt, const EPixelFormat::type format)
	{
		gles::GLenum	fmt  = 0;
		gles::GLenum	type = 0;
		uint			bpp  = 0;
		bool			res	 = GetFormat( ifmt, fmt, type, bpp, format );
		return ( res and ifmt != 0 );
	}

	// GetTexStorageFormat
	inline bool EPixelFormat::GetTexStorageFormat (gles::GLenum &ifmt, const EPixelFormat::type format)
	{
		gles::GLenum	fmt  = 0;
		gles::GLenum	type = 0;
		uint			bpp  = 0;
		bool			res	 = GetFormat( ifmt, fmt, type, bpp, format );
		return ( res and ifmt != 0 );
	}
	
	// GetBitPerPixel
	inline bool EPixelFormat::GetBitPerPixel (uint &bpp, const EPixelFormat::type format)
	{
		gles::GLenum	ifmt = 0;
		gles::GLenum	fmt  = 0;
		gles::GLenum	type = 0;
		bool			res	 = GetFormat( ifmt, fmt, type, bpp, format );
		return ( res and bpp > 0 );
	}

}	// Graphics
}	// Engine